import { InjectQueue } from '@nestjs/bullmq';
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Queue } from 'bullmq';
import { QueueName } from 'src/common/constants/queue.constant';
import { DataSource, FindManyOptions, Repository } from 'typeorm';
import { DemoCategory } from './entities/demo-category.entity';
import { Demo } from './entities/demo.entity';
import { DemoVo, DemoVoList } from './vo/demo.vo';
import { BatchCreateDemoDto } from './dto/create-demo.dto';

@Injectable()
export class DemoService {
  constructor(
    @InjectRepository(Demo)
    private readonly demoRepository: Repository<Demo>,
    private readonly dataSource: DataSource,
    @InjectQueue(QueueName.DEMO)
    private readonly demoQueue: Queue,
  ) {}

  /**
   * 新增数据
   * @param createDto
   * @returns
   */
  async createDemo(createDto: { name: string; owner: string }) {
    const data = await this.demoRepository.insert(
      this.demoRepository.create(createDto),
    );
    return data;
  }

  /**
   * 修改数据
   * @param id
   * @param updateDto
   * @returns
   */
  async updateDemo(id: string, updateDto: { name: string }) {
    const data = await this.demoRepository.update(id, updateDto);
    return data;
  }

  /**
   * 根据id创建或修改数据
   * @param saveDto
   * @returns
   */
  async saveDemo(saveDto: { id?: string; name: string; owner: string }) {
    const saved = await this.demoRepository.save(
      this.demoRepository.create(saveDto),
    );
    return saved;
  }

  /**
   * 标记删除
   * @param id
   * @returns
   */
  async removeDemo(id: string) {
    const data = await this.demoRepository.softDelete(id);
    return data;
  }

  /**
   * 分页查询
   * @param options
   * @returns
   */
  async findRowsAndTotal(
    options?: FindManyOptions<Demo>,
  ): Promise<{ rows: Demo[]; total: number }> {
    const [rows, total] = await this.demoRepository.findAndCount(options);

    // const userIds = rows.map((r) => r.owner);
    // const users = await User.findBy({
    //   id: In(userIds),
    // });
    // const userMap = users.reduce((memo, r) => {
    //   memo[r.id] = r;
    //   return memo;
    // }, {});
    // rows.forEach((r) => {
    //   r['isQuery'] = true;
    //   r['owner'] = userMap[r.owner];
    // });
    return {
      rows,
      total,
    };
  }

  async findDemoVos(options?: FindManyOptions<Demo>): Promise<DemoVoList> {
    const [list, total] = await this.demoRepository.findAndCount(options);
    const rows: DemoVo[] = list.map((r) => {
      delete r.owner;
      return {
        ...r,
        isQuery: true,
      };
    });
    return {
      rows,
      total,
    };
  }

  async testTransaction(categoryName: string, demoName: string, owner: string) {
    // 创建一个新的查询运行器
    const queryRunner = this.dataSource.createQueryRunner();
    // 现在让我们打开一个新的事务：
    await queryRunner.startTransaction();
    try {
      // 在这个事务中执行一些操作：
      let category = await queryRunner.manager.findOneBy(DemoCategory, {
        name: categoryName,
      });
      if (!category) {
        category = await queryRunner.manager.save(
          queryRunner.manager.create(DemoCategory, {
            name: categoryName,
          }),
        );
      }

      const savedDemo = await queryRunner.manager.save(
        queryRunner.manager.create(Demo, {
          name: demoName,
          categoryId: category.id,
          owner,
        }),
      );
      // 现在提交事务：
      await queryRunner.commitTransaction();
      return savedDemo;
    } catch (err) {
      // 由于发生错误，让我们回滚所做的更改
      await queryRunner.rollbackTransaction();
      throw err;
    } finally {
      // 您需要释放手动创建的查询运行器：
      await queryRunner.release();
    }
  }

  async findTableRows(tabel: string) {
    const tabelRepository = this.dataSource.getRepository(tabel);
    const [rows, total] = await tabelRepository.findAndCount();
    return {
      rows,
      total,
    };
  }

  async batchAdd(dto: BatchCreateDemoDto[], owner: string) {
    const jobIds = [];
    for (const data of dto) {
      const job = await this.demoQueue.add(
        'create',
        { ...data, owner },
        { delay: 10000 },
      );
      jobIds.push(job.id);
    }
    return jobIds;
  }

  async find(name?: string) {
    return await this.demoRepository.findOne({
      where: {
        name: name,
      },
    });
  }
}
